function Type(typeStr) {
	
	this.typeStr = typeStr;

	this.isArray = function() {
		return this.typeStr.indexOf(Types.ARRAY_PREFIX) == 0;
	}

	this.isNative = function() {
		return this.typeStr.indexOf(Types.NATIVE_PREFIX) == 0;
	}
	
	this.isInternal = function() {
		return this.typeStr.indexOf(Types.INTERNAL_PREFIX) == 0;
	}
	

	this.subtype = function() {
		if(this.isArray())
			return new Type(this.asString().substring(Types.ARRAY_PREFIX.length,this.asString().length));
		if(this.isNative())
			return new Type(this.asString().substring(Types.NATIVE_PREFIX.length,this.asString().length));
		return new Type(this.asString());
	}

	this.equals = function(t) {
		return t.asString() == this.typeStr;
	}
	
	this.equalsAny = function(ts) {
		for(var i = 0; i < ts.length; i++)
			if(ts[i].equals(this)) return true;
		return false;
	}
	
	this.asString = function() {
		return this.typeStr;
	}
	
	this.toString = this.asString;
}

//type overloaded
function TypeFromObject(obj) {
	
	Type.call(this,getType(obj).asString());
	
	function getType(o) {
		if(o == undefined || o == null) return Types.UNKNOWN;
		
		if(typeof(o) == "number" || o.constructor == Number) {
			if(parseInt(o) == o)
				return Types.INT;
			return Types.DOUBLE;
		}
		if(typeof(o) == "string" || o.constructor == String)  return Types.STRING;
		if(typeof(o) == "boolean" || o.constructor == Boolean) return Types.BOOLEAN;
		if(o.constructor == Array) {
			for(var i = 0; i < o.length; i++) {
				if(getType(o[i]).isNative())
					return Types.toNative(o);
			}
			var sub = Types.UNKNOWN;
			if(o.length > 0)
				sub = getType(o[0]);
			if(!sub.isNative())
				return Types.toArray(sub);
		}
		return Types.toNative(o);
	}
	
}
